//
//  ZCommandClass.h
//  Part of Z-Way.C library
//
//  Created by Alex Skalozub on 2/1/12.
//  Based on Z-Way source code written by Christian Paetz and Poltorak Serguei
//
//  Copyright (c) 2012 Z-Wave.Me
//  All rights reserved
//  info@z-wave.me
//
//  This source file is subject to the terms and conditions of the
//  Z-Wave.Me Software License Agreement which restricts the manner
//  in which it may be used.
//

#ifndef zway_command_class_h
#define zway_command_class_h

#include "ZLog.h"

// needed in several places
#define WAKE_UP_NO_MORE_INFORMATION 0x08
#define SECURITY_COMMANDS_SUPPORTED_GET 0x02
#define SECURITY_COMMANDS_SUPPORTED_REPORT 0x03
#define SECURITY_NONCE_REPORT 0x80
#define SECURITY_NONCE_GET    0x40
#define SECURITY_MESSAGE_ENCAPSULATION 0x81
#define SECURITY_MESSAGE_ENCAPSULATION_NONCE_GET 0xC1
#define SECURITY_2_NONCE_GET             0x01
#define SECURITY_2_NONCE_REPORT          0x02
#define SECURITY_2_MESSAGE_ENCAPSULATION 0x03
#define DEVICE_RESET_LOCALLY_NOTIFICATION 0x01

#define MANUFACTURER_SPECIFIC_GET	 0x04

#define NONCE_GET_INTERVAL	1000

#define FRAGMENT_MAX_PAYLOAD	         39   // CC:0055.02.00.21.001

#define MAX_SEND_DATA_PACKET_SIZE        45 // from docs 54 but for safety
#define MAX_SEND_DATA_MULTI_PACKET_SIZE  25 // from docs


struct _ZCommandClass 
{
    ZWBYTE id;
    ZWCSTR name;
    ZWBOOL isTransport:1;
    ZWBOOL isSecure:1;
    ZCommandClassInit init_handler;
    ZCommandClassInterview interview_handler;
    ZCommandClassCommand command_handler;
    ZCommandClassCommandType command_type_handler;
    ZCommandClassCommandSupervisionHandler command_supervision_handler;
    ZCommandClassPostLoad loaded_handler;
    ZCommandClassTimer timer_handler;
    float timer_interval;
};

enum JobMode_t
{
    JobModeGet,
    JobModeSetReportTransportTrySupervision,
    JobModeSetReportTransportForceSupervision
};
typedef enum JobMode_t JobMode;

enum JobSupervisionMode_t
{
    JobSupervisionModeDoEncapsulate,
    JobSupervisionModeTryEncapsulate,
    JobSupervisionModeDontEncapsulate
};
typedef enum JobSupervisionMode_t JobSupervisionMode;

ZWEXPORT_PRIVATE const ZCommandClass * _zway_get_command_by_id(ZWBYTE id);

const ZCommandClass * _zway_get_command_by_name(ZWCSTR name);

ZWError _zway_cc_run(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE length, const ZWBYTE *data, ZJobList onBehalfOf, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_report(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE length, const ZWBYTE *data, ZJobList onBehalfOf, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_request(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE length, const ZWBYTE *data, ZJobList onBehalfOf, const ZWBYTE expected_reply_payload_size, const ZWBYTE *expected_reply_payload, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void *callbackArg);

ZWError _zway_cc_run_ex(ZWay zway, ZWCSTR description, ZWBYTE instance_id, ZWBYTE my_instance_id, ZCommand command, ZWBYTE length, const ZWBYTE *data, ZJobList onBehalfOf, JobMode jobMode, ZWBOOL security, ZJob *pjob, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_run1(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE arg1, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_run2(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE arg1, ZWBYTE arg2, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_run3(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE arg1, ZWBYTE arg2, ZWBYTE arg3, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_run4(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE arg1, ZWBYTE arg2, ZWBYTE arg3, ZWBYTE arg4, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_report1(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE arg1, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_report2(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE arg1, ZWBYTE arg2, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_report3(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE arg1, ZWBYTE arg2, ZWBYTE arg3, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_report4(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE arg1, ZWBYTE arg2, ZWBYTE arg3, ZWBYTE arg4, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_request1(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE arg1, ZWBYTE expected_reply_payload_size, ZWBYTE * expected_reply_payload, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_request2(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE arg1, ZWBYTE arg2, ZWBYTE expected_reply_payload_size, ZWBYTE * expected_reply_payload, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_request3(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE arg1, ZWBYTE arg2, ZWBYTE arg3, ZWBYTE expected_reply_payload_size, ZWBYTE * expected_reply_payload, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_request4(ZWay zway, ZWCSTR description, ZCommand command, ZWBYTE arg1, ZWBYTE arg2, ZWBYTE arg3, ZWBYTE arg4, ZWBYTE expected_reply_payload_size, ZWBYTE * expected_reply_payload, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWBOOL _zway_reply_handle(ZWay zway, ZWNODE node_id, ZWBYTE instance_id, ZWBYTE expected_reply_size, ZWBYTE * expected_reply);

ZWError _zway_cc_broadcast_run1(ZWay zway, ZWCSTR description, ZWBYTE ccId, ZWBYTE arg1, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_broadcast_run2(ZWay zway, ZWCSTR description, ZWBYTE ccId, ZWBYTE arg1, ZWBYTE arg2, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError _zway_cc_call_handler(ZWay zway, ZInstance instance, ZWNODE node_id, ZWBYTE instance_id, ZWBYTE length, const ZWBYTE *data);
ZWError _zway_cc_call_is_handling_allowed(ZWay zway, ZInstance instance, ZWBYTE cc_id, ZWBYTE cmd_id, ZWNODE node_id, ZWBYTE instance_id);

void _zway_cc_log(ZWay zway, ZCommand command, ZWLogLevel level, PRINTF_FORMAT_STRING ZWCSTR message, ...) __printflike(4, 5);

ZWBOOL _zway_command_supported_by_controller(ZWay zway, ZWBYTE ccId);

ZWBOOL _zway_supervision_shall_encapsulate(ZWay zway, ZCommand command, ZWBYTE cmd);
ZWBOOL _zway_supervision_shall_encapsulate_ex(ZWay zway, ZCommand command, ZWBYTE cmd, JobSupervisionMode supervisionMode);

ZWBOOL _zway_device_is_supported_unsolicited_report_on_set(ZWay zway, ZCommand command);

void _zway_find_matching_request(ZWay zway, ZWNODE node_id, ZWBYTE instance_id, ZWBYTE reply_size, ZWBYTE * reply, ZWBYTE *length, const ZWBYTE **payload, ZWBYTE *key_class, const char **description);

void _zway_reply_delay(ZWay zway, ZWNODE node_id, ZWBYTE instance_id, ZWBYTE expected_reply_size, ZWBYTE * expected_reply, int delay);

ZWError _zway_cc_call_supervision_handler(ZWay zway, ZCommand supervisionCommand, ZWNODE node_id, ZWBYTE instance_id, ZWBYTE length, const ZWBYTE *data, ZWBYTE key_class);

ZJob * _zway_cc_added_job(ZWay zway);

typedef void (*ZJobCustomWrapperCallback)(ZWay zway, ZCommand command, void* arg);

ZWError _zway_wrap_command_callback(ZWay zway, ZCommand command, ZJobCustomWrapperCallback wrapperSuccessCallback, ZJobCustomWrapperCallback wrapperFailureCallback, void *wrapperCallbackArgPtr, ZJobCustomCallback *successCallbackPtr, ZJobCustomCallback *failureCallback, void **callbackArgPtr);

ZWError _zway_delay_get_prepare_callbacks(ZWay zway, ZCommand command, void (*get)(ZWay, ZCommand, void *), void* getArg, ZJobCustomCallback* successCallbackPtr, ZJobCustomCallback* failureCallbackPtr, void** callbackArgPtr);

ZJob _zway_try_multi_cmd_encapsulation(ZWay zway, ZDevice device, ZJob job, ZWBYTE sec);
ZJob _zway_try_multi_channel_multicast_encapsulation(ZWay zway, ZDevice device, ZJob nextJob, ZWBYTE sec);
ZWBOOL _zway_try_transport_service_encapsulation(ZWay zway, ZDevice device, ZJob nextJob);

ZWBOOL _zway_is_security_requested(ZWay zway, ZDevice device);

// defined in ZWorkerThread.c, Security.c SecurityS2.c
ZWBOOL filter_active_unsecure(const ZJob job);
ZWBOOL filter_multicmd(const ZJob job);
ZWBOOL filter_waiting_security_s2(const ZJob job);
ZWBOOL filter_waiting_security(const ZJob job);

typedef struct _ZWayArgumentDeviceIdAndInstanceId_s
{
    union
    {
        struct
        {
            ZWNODE deviceId;
            ZWBYTE instanceId;
        } value;
        void *arg;
    };
} _ZWayArgumentDeviceIdAndInstanceId_t;

static inline void *_zway_argument_generate_deviceid_and_instanceid(ZWNODE deviceId, ZWBYTE instanceId)
{
    _ZWayArgumentDeviceIdAndInstanceId_t init;

    init.value.deviceId = deviceId;
    init.value.instanceId = instanceId;
    return init.arg;
};

static inline _ZWayArgumentDeviceIdAndInstanceId_t _zway_argument_extract_deviceid_and_instanceid(void *arg)
{
    _ZWayArgumentDeviceIdAndInstanceId_t init;

    init.arg = arg;
    return init;
};

#endif
